Passed
Push — master ( eb826c...125aa5 )
by EMP
01:30
created

main.js ➔ addAccountToTable   B

Complexity

Conditions 6

Size

Total Lines 26
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 20
dl 0
loc 26
rs 8.4666
c 0
b 0
f 0
cc 6
1
"use strict";
2
3
sodium.ready.then(function() {
1 ignored issue
show
Bug introduced by
The variable sodium seems to be never declared. If this is a global, consider adding a /** global: sodium */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
4
5
const ae = new AllEars(function(ok) {
1 ignored issue
show
Bug introduced by
The variable AllEars seems to be never declared. If this is a global, consider adding a /** global: AllEars */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
6
	if (ok) {
7
		const greeting = localStorage.greeting;
1 ignored issue
show
Bug introduced by
The variable localStorage seems to be never declared. If this is a global, consider adding a /** global: localStorage */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
8
		if (greeting) {
9
			document.getElementById("greeting").textContent = greeting;
10
			document.getElementById("txt_pg").value = greeting;
11
		}
12
13
		document.getElementById("txt_skey").style.background = "#466";
14
		document.getElementById("txt_skey").maxLength = "64";
15
	} else {
16
		console.log("Failed to load All-Ears");
17
	}
18
});
19
20
function TabState(cur, max, btnDele, btnUpdt) {
21
	this.cur = cur;
22
	this.max = max;
23
	this.btnDele = btnDele;
24
	this.btnUpdt = btnUpdt;
25
}
26
27
const tabs = [
28
	new TabState(0, 0, false, true), // Inbox
29
	new TabState(0, 0, false, true), // Outbx
30
	new TabState(0, 2, true, false), // Write
31
	new TabState(0, 2, false, false), // Notes
32
	new TabState(0, 3, false, true) // Tools
33
];
34
35
let showHeaders = false;
36
37
let tab = 0;
38
const TAB_INBOX = 0;
39
const TAB_DRBOX = 1;
40
const TAB_WRITE = 2;
41
const TAB_NOTES = 3;
42
const TAB_TOOLS = 4;
43
44
// Helper functions
45
function getCountryName(countryCode) {
46
	switch (countryCode) {
47
		case "DZ": return "Algeria";
48
		case "AO": return "Angola";
49
		case "BJ": return "Benin";
50
		case "BW": return "Botswana";
51
		case "BF": return "Burkina Faso";
52
		case "BI": return "Burundi";
53
		case "CV": return "Cabo Verde";
54
		case "CM": return "Cameroon";
55
		case "CF": return "Central African Republic";
56
		case "TD": return "Chad";
57
		case "KM": return "Comoros";
58
		case "CD": return "Congo";
59
		case "DJ": return "Djibouti";
60
		case "EG": return "Egypt";
61
		case "GQ": return "Equatorial Guinea";
62
		case "ER": return "Eritrea";
63
		case "SZ": return "Eswatini";
64
		case "ET": return "Ethiopia";
65
		case "GA": return "Gabon";
66
		case "GM": return "Gambia";
67
		case "GH": return "Ghana";
68
		case "GW": return "Guinea-Bissau";
69
		case "GN": return "Guinea";
70
		case "CI": return "Ivory Coast";
71
		case "KE": return "Kenya";
72
		case "LS": return "Lesotho";
73
		case "LR": return "Liberia";
74
		case "LY": return "Libya";
75
		case "MG": return "Madagascar";
76
		case "MW": return "Malawi";
77
		case "ML": return "Mali";
78
		case "MR": return "Mauritania";
79
		case "MU": return "Mauritius";
80
		case "YT": return "Mayotte";
81
		case "MA": return "Morocco";
82
		case "MZ": return "Mozambique";
83
		case "NA": return "Namibia";
84
		case "NE": return "Niger";
85
		case "NG": return "Nigeria";
86
		case "CG": return "Republic of the Congo";
87
		case "RW": return "Rwanda";
88
		case "RE": return "Réunion";
89
		case "SH": return "Saint Helena";
90
		case "SN": return "Senegal";
91
		case "SC": return "Seychelles";
92
		case "SL": return "Sierra Leone";
93
		case "SO": return "Somalia";
94
		case "ZA": return "South Africa";
95
		case "SS": return "South Sudan";
96
		case "SD": return "Sudan";
97
		case "ST": return "São Tomé and Príncipe";
98
		case "TZ": return "Tanzania";
99
		case "TG": return "Togo";
100
		case "TN": return "Tunisia";
101
		case "UG": return "Uganda";
102
		case "EH": return "Western Sahara";
103
		case "ZM": return "Zambia";
104
		case "ZW": return "Zimbabwe";
105
		case "AQ": return "Antarctica";
106
		case "BV": return "Bouvet Island";
107
		case "TF": return "French Southern Territories";
108
		case "HM": return "Heard Island and McDonald Islands";
109
		case "GS": return "South Georgia and the South Sandwich Islands";
110
		case "AF": return "Afghanistan";
111
		case "AM": return "Armenia";
112
		case "AZ": return "Azerbaijan";
113
		case "BH": return "Bahrain";
114
		case "BD": return "Bangladesh";
115
		case "BT": return "Bhutan";
116
		case "IO": return "British Indian Ocean Territory";
117
		case "BN": return "Brunei";
118
		case "KH": return "Cambodia";
119
		case "CN": return "China";
120
		case "CC": return "Cocos [Keeling] Islands";
121
		case "GE": return "Georgia";
122
		case "JO": return "Hashemite Kingdom of Jordan";
123
		case "HK": return "Hong Kong";
124
		case "IN": return "India";
125
		case "ID": return "Indonesia";
126
		case "IR": return "Iran";
127
		case "IQ": return "Iraq";
128
		case "IL": return "Israel";
129
		case "JP": return "Japan";
130
		case "KZ": return "Kazakhstan";
131
		case "KW": return "Kuwait";
132
		case "KG": return "Kyrgyzstan";
133
		case "LA": return "Laos";
134
		case "LB": return "Lebanon";
135
		case "MO": return "Macao";
136
		case "MY": return "Malaysia";
137
		case "MV": return "Maldives";
138
		case "MN": return "Mongolia";
139
		case "MM": return "Myanmar";
140
		case "NP": return "Nepal";
141
		case "KP": return "North Korea";
142
		case "OM": return "Oman";
143
		case "PK": return "Pakistan";
144
		case "PS": return "Palestine";
145
		case "PH": return "Philippines";
146
		case "QA": return "Qatar";
147
		case "SA": return "Saudi Arabia";
148
		case "SG": return "Singapore";
149
		case "KR": return "South Korea";
150
		case "LK": return "Sri Lanka";
151
		case "SY": return "Syria";
152
		case "TW": return "Taiwan";
153
		case "TJ": return "Tajikistan";
154
		case "TH": return "Thailand";
155
		case "TR": return "Turkey";
156
		case "TM": return "Turkmenistan";
157
		case "AE": return "United Arab Emirates";
158
		case "UZ": return "Uzbekistan";
159
		case "VN": return "Vietnam";
160
		case "YE": return "Yemen";
161
		case "AL": return "Albania";
162
		case "AD": return "Andorra";
163
		case "AT": return "Austria";
164
		case "BY": return "Belarus";
165
		case "BE": return "Belgium";
166
		case "BA": return "Bosnia and Herzegovina";
167
		case "BG": return "Bulgaria";
168
		case "HR": return "Croatia";
169
		case "CY": return "Cyprus";
170
		case "CZ": return "Czechia";
171
		case "DK": return "Denmark";
172
		case "EE": return "Estonia";
173
		case "FO": return "Faroe Islands";
174
		case "FI": return "Finland";
175
		case "FR": return "France";
176
		case "DE": return "Germany";
177
		case "GI": return "Gibraltar";
178
		case "GR": return "Greece";
179
		case "GG": return "Guernsey";
180
		case "HU": return "Hungary";
181
		case "IS": return "Iceland";
182
		case "IE": return "Ireland";
183
		case "IM": return "Isle of Man";
184
		case "IT": return "Italy";
185
		case "JE": return "Jersey";
186
		case "XK": return "Kosovo";
187
		case "LV": return "Latvia";
188
		case "LI": return "Liechtenstein";
189
		case "LU": return "Luxembourg";
190
		case "MT": return "Malta";
191
		case "MC": return "Monaco";
192
		case "ME": return "Montenegro";
193
		case "NL": return "Netherlands";
194
		case "MK": return "North Macedonia";
195
		case "NO": return "Norway";
196
		case "PL": return "Poland";
197
		case "PT": return "Portugal";
198
		case "LT": return "Republic of Lithuania";
199
		case "MD": return "Republic of Moldova";
200
		case "RO": return "Romania";
201
		case "RU": return "Russia";
202
		case "SM": return "San Marino";
203
		case "RS": return "Serbia";
204
		case "SK": return "Slovakia";
205
		case "SI": return "Slovenia";
206
		case "ES": return "Spain";
207
		case "SJ": return "Svalbard and Jan Mayen";
208
		case "SE": return "Sweden";
209
		case "CH": return "Switzerland";
210
		case "UA": return "Ukraine";
211
		case "GB": return "United Kingdom";
212
		case "VA": return "Vatican City";
213
		case "AX": return "Åland";
214
		case "AI": return "Anguilla";
215
		case "AG": return "Antigua and Barbuda";
216
		case "AW": return "Aruba";
217
		case "BS": return "Bahamas";
218
		case "BB": return "Barbados";
219
		case "BZ": return "Belize";
220
		case "BM": return "Bermuda";
221
		case "BQ": return "Bonaire, Sint Eustatius, and Saba";
222
		case "VG": return "British Virgin Islands";
223
		case "CA": return "Canada";
224
		case "KY": return "Cayman Islands";
225
		case "CR": return "Costa Rica";
226
		case "CU": return "Cuba";
227
		case "CW": return "Curaçao";
228
		case "DM": return "Dominica";
229
		case "DO": return "Dominican Republic";
230
		case "SV": return "El Salvador";
231
		case "GL": return "Greenland";
232
		case "GD": return "Grenada";
233
		case "GP": return "Guadeloupe";
234
		case "GT": return "Guatemala";
235
		case "HT": return "Haiti";
236
		case "HN": return "Honduras";
237
		case "JM": return "Jamaica";
238
		case "MQ": return "Martinique";
239
		case "MX": return "Mexico";
240
		case "MS": return "Montserrat";
241
		case "NI": return "Nicaragua";
242
		case "PA": return "Panama";
243
		case "PR": return "Puerto Rico";
244
		case "BL": return "Saint Barthélemy";
245
		case "LC": return "Saint Lucia";
246
		case "MF": return "Saint Martin";
247
		case "PM": return "Saint Pierre and Miquelon";
248
		case "VC": return "Saint Vincent and the Grenadines";
249
		case "SX": return "Sint Maarten";
250
		case "KN": return "St Kitts and Nevis";
251
		case "TT": return "Trinidad and Tobago";
252
		case "TC": return "Turks and Caicos Islands";
253
		case "VI": return "U.S. Virgin Islands";
254
		case "US": return "United States";
255
		case "AS": return "American Samoa";
256
		case "AU": return "Australia";
257
		case "CX": return "Christmas Island";
258
		case "CK": return "Cook Islands";
259
		case "TL": return "Democratic Republic of Timor-Leste";
260
		case "FM": return "Federated States of Micronesia";
261
		case "FJ": return "Fiji";
262
		case "PF": return "French Polynesia";
263
		case "GU": return "Guam";
264
		case "KI": return "Kiribati";
265
		case "MH": return "Marshall Islands";
266
		case "NR": return "Nauru";
267
		case "NC": return "New Caledonia";
268
		case "NZ": return "New Zealand";
269
		case "NU": return "Niue";
270
		case "NF": return "Norfolk Island";
271
		case "MP": return "Northern Mariana Islands";
272
		case "PW": return "Palau";
273
		case "PG": return "Papua New Guinea";
274
		case "PN": return "Pitcairn Islands";
275
		case "WS": return "Samoa";
276
		case "SB": return "Solomon Islands";
277
		case "TK": return "Tokelau";
278
		case "TO": return "Tonga";
279
		case "TV": return "Tuvalu";
280
		case "UM": return "U.S. Minor Outlying Islands";
281
		case "VU": return "Vanuatu";
282
		case "WF": return "Wallis and Futuna";
283
		case "AR": return "Argentina";
284
		case "BO": return "Bolivia";
285
		case "BR": return "Brazil";
286
		case "CL": return "Chile";
287
		case "CO": return "Colombia";
288
		case "EC": return "Ecuador";
289
		case "FK": return "Falkland Islands";
290
		case "GF": return "French Guiana";
291
		case "GY": return "Guyana";
292
		case "PY": return "Paraguay";
293
		case "PE": return "Peru";
294
		case "SR": return "Suriname";
295
		case "UY": return "Uruguay";
296
		case "VE": return "Venezuela";
297
	}
0 ignored issues
show
Comprehensibility introduced by
There is no default case in this switch, so nothing gets returned when all cases fail. You might want to consider adding a default or return undefined explicitly.
Loading history...
298
}
299
300
function getCountryFlag(countryCode) {
301
	return sodium.to_string(new Uint8Array([
1 ignored issue
show
Bug introduced by
The variable sodium seems to be never declared. If this is a global, consider adding a /** global: sodium */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
302
		240, 159, 135, 166 + countryCode.codePointAt(0) - 65,
303
		240, 159, 135, 166 + countryCode.codePointAt(1) - 65
304
	]));
305
}
306
307
function getClockIcon(d) {
308
	const h24 = d.getUTCHours();
309
	let h12 = (h24 === 0 ? 12 : ((h24 > 12) ? h24 - 12 : h24));
310
311
	const m60 = (d.getUTCMinutes() * 60) + d.getUTCSeconds();
312
	let m30 = 0;
313
	if (m60 <= 900) { // <= 15: round down to this hour
314
		m30 = 0;
315
	} else if (m60 > 900 && m60 < 2700) { // 15..45: round to half-past this hour
316
		m30 = 12;
317
	} else { // >= 45: round up to next hour
318
		h12++;
319
		m30 = 0;
320
	}
321
322
	return "&#" + ((128335 + h12) + m30) + ";";
323
}
324
325
function getMsgId(num) {
326
	let i;
327
	if (ae.GetExtMsgHeaders(num).toLowerCase().slice(0, 11) === "message-id:") {
328
		i = 0;
329
	} else {
330
		i = ae.GetExtMsgHeaders(num).toLowerCase().indexOf("\nmessage-id:");
331
		if (i < 1) return "ERR";
332
		i++;
333
	}
334
335
	const x = ae.GetExtMsgHeaders(num).slice(i + 11).trim();
336
	if (x[0] !== "<") return "ERR2";
337
	return x.slice(1, x.indexOf(">"));
338
}
339
340
function clearDisplay() {
341
	let el = document.getElementById("midright").getElementsByTagName("img");
342
	if (el.length !== 1) el = document.getElementById("midright").getElementsByTagName("audio");
343
	if (el.length !== 1) el = document.getElementById("midright").getElementsByTagName("video");
344
	if (el.length !== 1) el = document.getElementById("midright").getElementsByTagName("embed");
345
	if (el.length !== 1) el = document.getElementById("midright").getElementsByTagName("iframe");
346
	if (el.length !== 1) return;
347
348
	URL.revokeObjectURL(el[0].src);
1 ignored issue
show
Bug introduced by
The variable URL seems to be never declared. If this is a global, consider adding a /** global: URL */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
349
	el[0].remove();
350
}
351
352
function displayFile(num) {
353
	clearDisplay();
354
355
	document.getElementById("midright").scroll(0, 0);
356
	document.getElementById("midright").setAttribute("data-msgid", ae.GetUplMsgIdHex(num));
357
	document.getElementById("btn_reply").disabled = true;
358
	document.getElementById("btn_mdele").disabled = false;
359
	document.getElementById("midright").children[0].hidden = true;
360
	document.getElementById("midright").children[1].textContent = ae.GetUplMsgTitle(num);
361
362
	switch (ae.GetUplMsgType(num)) {
363
		case "text": {
364
			document.getElementById("midright").children[2].hidden = false;
365
			document.getElementById("midright").children[2].textContent = sodium.to_string(ae.GetUplMsgBody(num));
1 ignored issue
show
Bug introduced by
The variable sodium seems to be never declared. If this is a global, consider adding a /** global: sodium */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
366
		break;}
367
368
		case "image": {
369
			document.getElementById("midright").children[2].hidden = true;
370
			const img = document.createElement("img");
371
			img.src = URL.createObjectURL(new Blob([ae.GetUplMsgBody(num).buffer]));
2 ignored issues
show
Bug introduced by
The variable Blob seems to be never declared. If this is a global, consider adding a /** global: Blob */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
Bug introduced by
The variable URL seems to be never declared. If this is a global, consider adding a /** global: URL */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
372
			document.getElementById("midright").appendChild(img);
373
374
			img.onclick = function() {
375
				if (!document.fullscreen)
376
					img.requestFullscreen();
377
				else
378
					document.exitFullscreen();
379
			};
380
		break;}
381
382
		case "audio": {
383
			document.getElementById("midright").children[2].hidden = true;
384
			const el = document.createElement("audio");
385
			el.controls = "controls";
386
			el.src = URL.createObjectURL(new Blob([ae.GetUplMsgBody(num).buffer]));
387
			document.getElementById("midright").appendChild(el);
388
		break;}
389
390
		case "video": {
391
			document.getElementById("midright").children[2].hidden = true;
392
			const el = document.createElement("video");
393
			el.controls = "controls";
394
			el.src = URL.createObjectURL(new Blob([ae.GetUplMsgBody(num).buffer]));
395
			document.getElementById("midright").appendChild(el);
396
		break;}
397
398
		case "pdf": {
399
			document.getElementById("midright").children[2].hidden = true;
400
			const el = document.createElement("embed");
401
			el.type = "application/pdf";
402
			el.src = URL.createObjectURL(new Blob([ae.GetUplMsgBody(num).buffer], {type: "application/pdf"}));
403
			document.getElementById("midright").appendChild(el);
404
		break;}
405
406
		case "html": {
407
			document.getElementById("midright").children[2].hidden = true;
408
			const el = document.createElement("iframe");
409
			el.allow = "";
410
			el.sandbox = "";
411
			el.csp = "base-uri 'none'; child-src 'none'; connect-src 'none'; default-src 'none'; font-src 'none'; form-action 'none'; frame-ancestors 'none'; frame-src 'none'; img-src 'none'; manifest-src 'none'; media-src 'none'; object-src 'none'; script-src 'none'; style-src 'none'; worker-src 'none';";
412
			el.srcdoc = sodium.to_string(ae.GetUplMsgBody(num).buffer);
413
			document.getElementById("midright").appendChild(el);
414
		break;}
415
	}
416
}
417
418
function displayMsg(isInt, num) {
419
	clearDisplay();
420
421
	document.getElementById("btn_mdele").disabled = false;
422
	document.getElementById("midright").scroll(0, 0);
423
	document.getElementById("midright").setAttribute("data-msgid", isInt? ae.GetIntMsgIdHex(num) : ae.GetExtMsgIdHex(num));
424
425
	const ts = isInt? ae.GetIntMsgTime(num) : ae.GetExtMsgTime(num);
426
427
	document.getElementById("btn_reply").disabled = false;
428
	document.getElementById("btn_reply").onclick = function() {
429
		document.getElementById("write_recv").value = isInt? ae.GetIntMsgFrom(num) : ae.GetExtMsgReplyAddress(num);
430
		document.getElementById("write_subj").value = isInt? ae.GetIntMsgTitle(num) : ae.GetExtMsgTitle(num);
431
		if (!document.getElementById("write_subj").value.startsWith("Re:")) document.getElementById("write_subj").value = "Re: " + document.getElementById("write_subj").value;
432
		document.querySelector("#write2_pkey > input").value = isInt? ae.GetIntMsgFromPk(num) : "";
433
434
		document.getElementById("write_recv").readOnly = !isInt;
435
		document.getElementById("write_subj").readOnly = !isInt;
436
		document.getElementById("write_subj").setAttribute("data-replyid", isInt? "" : getMsgId(num));
437
438
		tabs[TAB_WRITE].cur = 0;
439
		document.getElementById("btn_write").disabled = false;
440
		document.getElementById("btn_write").click();
441
		document.getElementById("write_body").focus();
442
443
		for (const opt of document.getElementById("write_from").options) {
444
			if (opt.value === (isInt ? ae.GetIntMsgTo(num) : ae.GetExtMsgTo(num))) {
445
				opt.selected = true;
446
			}
447
		}
448
	};
449
450
	document.getElementById("midright").children[0].hidden = false;
451
	document.getElementById("midright").children[2].hidden = false;
452
453
	if (isInt) {
454
		document.getElementById("midright").children[1].textContent = ae.GetIntMsgTitle(num);
455
		document.getElementById("midright").children[2].textContent = ae.GetIntMsgBody(num);
456
	} else {
457
		document.getElementById("midright").children[2].innerHTML = "";
458
459
		const headers = document.createElement("p");
460
		headers.textContent = ae.GetExtMsgHeaders(num);
461
		headers.className = "mono";
462
		headers.hidden = !showHeaders;
463
		document.getElementById("midright").children[2].appendChild(headers);
464
465
		const body = document.createElement("p");
466
		body.textContent = ae.GetExtMsgBody(num);
467
		document.getElementById("midright").children[2].appendChild(body);
468
469
		document.getElementById("midright").children[1].textContent = ae.GetExtMsgTitle(num);
470
		document.getElementById("midright").children[1].onclick = function() {showHeaders = !showHeaders; headers.hidden = !showHeaders;};
471
		document.getElementById("midright").children[1].style.cursor = "pointer";
472
	}
473
474
	document.getElementById("readmsg_envto").textContent = isInt ? ae.GetIntMsgTo(num) : ae.GetExtMsgTo(num);
475
476
	const tzOs = new Date().getTimezoneOffset();
477
	const tz = ((tzOs < 0) ? "+" : "-") + Math.floor(tzOs / -60).toString().padStart(2, "0") + (tzOs % 60 * -1).toString().padStart(2, "0");
478
	const msgDate = new Date((ts * 1000) + (tzOs * -60000));
479
480
	document.getElementById("readmsg_date").children[0].innerHTML = getClockIcon(msgDate);
481
	document.getElementById("readmsg_date").children[1].textContent = msgDate.toISOString().slice(0, 19).replace("T", " ") + " " + tz;
482
483
	if (!isInt) {
484
		document.getElementById("readmsg_ip").hidden = false;
485
		document.getElementById("readmsg_country").hidden = false;
486
		document.getElementById("readmsg_tls").hidden = false;
487
		document.getElementById("readmsg_greet").hidden = false;
488
489
		const cc = ae.GetExtMsgCountry(num);
490
491
		document.getElementById("readmsg_ip").children[0].textContent = ae.GetExtMsgIp(num);
492
		document.getElementById("readmsg_country").textContent = getCountryFlag(cc) + " " + getCountryName(cc);
493
		document.getElementById("readmsg_tls").children[0].textContent = ae.GetExtMsgTLS(num);
494
		document.getElementById("readmsg_greet").children[0].textContent = ae.GetExtMsgGreet(num);
495
		document.getElementById("readmsg_envfrom").textContent = ae.GetExtMsgFrom(num);
496
497
		let flagText = "";
498
		if (!ae.GetExtMsgFlagVPad(num)) flagText += "<abbr title=\"Invalid padding\">PAD</abbr> ";
499
		if (!ae.GetExtMsgFlagVSig(num)) flagText += "<abbr title=\"Invalid signature\">SIG</abbr> ";
500
		if (!ae.GetExtMsgFlagPExt(num)) flagText += "<abbr title=\"The sender did not use the Extended (ESMTP) protocol\">SMTP</abbr> ";
501
		if (!ae.GetExtMsgFlagQuit(num)) flagText += "<abbr title=\"The sender did not issue the required QUIT command\">QUIT</abbr> ";
502
		if (ae.GetExtMsgFlagRare(num)) flagText += "<abbr title=\"The sender issued unusual command(s)\">RARE</abbr> ";
503
		if (ae.GetExtMsgFlagFail(num)) flagText += "<abbr title=\"The sender issued invalid command(s)\">FAIL</abbr> ";
504
		if (ae.GetExtMsgFlagPErr(num)) flagText += "<abbr title=\"The sender violated the protocol\">PROT</abbr> ";
505
		document.getElementById("readmsg_flags").children[0].innerHTML = flagText.trim();
506
	} else {
507
		document.getElementById("readmsg_ip").hidden = true;
508
		document.getElementById("readmsg_country").hidden = true;
509
		document.getElementById("readmsg_greet").hidden = true;
510
511
		document.getElementById("readmsg_tls").hidden = false;
512
		document.getElementById("readmsg_tls").children[0].textContent = ae.GetIntMsgFromPk(num);
513
514
		let symbol = "<span title=\"Invalid level\">&#x26a0;</span>";
515
		if (ae.GetIntMsgFrom(num) === "system") {if (ae.GetIntMsgLevel(num) === 3) symbol = "<span title=\"System\">&#x1f162;</span>";} // S (System)
516
		else if (ae.GetIntMsgLevel(num) === 0) symbol = "<span title=\"Level 0 User\">&#x1f10c;</span>"; // 0
517
		else if (ae.GetIntMsgLevel(num) === 1) symbol = "<span title=\"Level 1 User\">&#x278a;</span>"; // 1
518
		else if (ae.GetIntMsgLevel(num) === 2) symbol = "<span title=\"Level 2 User\">&#x278b;</span>"; // 2
519
		else if (ae.GetIntMsgLevel(num) === 3) symbol = "<span title=\"Administrator\">&#x1f150;</span>"; // A (Admin)
520
		document.getElementById("readmsg_envfrom").innerHTML = symbol + " " + ae.GetIntMsgFrom(num);
521
522
		let flagText = "";
523
		if (!ae.GetIntMsgFlagVPad(num)) flagText += "<abbr title=\"Invalid padding\">PAD</abbr> ";
524
		if (!ae.GetIntMsgFlagVSig(num)) flagText += "<abbr title=\"Invalid signature\">SIG</abbr> ";
525
		if (ae.GetIntMsgFlagE2ee(num)) flagText += "<abbr title=\"End-to-end encrypted\">E2EE</abbr> ";
526
		document.getElementById("readmsg_flags").children[0].innerHTML = flagText.trim();
527
	}
528
}
529
530
// Interface
531
function addMsg(isInt, i) {
532
	const row = document.getElementById("tbl_inbox").insertRow(-1);
533
	row.setAttribute("data-msgid", isInt? ae.GetIntMsgIdHex(i) : ae.GetExtMsgIdHex(i));
534
535
	const cellTime = row.insertCell(-1);
536
	const cellSubj = row.insertCell(-1);
537
	const cellSnd1 = row.insertCell(-1);
538
	const cellSnd2 = row.insertCell(-1);
539
540
	const ts = isInt? ae.GetIntMsgTime(i) : ae.GetExtMsgTime(i);
541
	cellTime.setAttribute("data-ts", ts);
542
	cellTime.textContent = new Date((ts * 1000) + (new Date().getTimezoneOffset() * -60000)).toISOString().slice(0, 10);
543
544
	cellSubj.textContent = isInt? ae.GetIntMsgTitle(i) : ae.GetExtMsgTitle(i);
545
546
	if (isInt) {
547
		cellSnd1.textContent = ae.GetIntMsgFrom(i);
548
		cellSnd1.className = (ae.GetIntMsgFrom(i).length === 16) ? "mono" : "";
549
	} else {
550
		const from1 = ae.GetExtMsgFrom(i);
551
		const from2 = from1.substring(from1.indexOf("@") + 1);
552
		const cc = ae.GetExtMsgCountry(i);
553
554
		cellSnd1.textContent = from1.substring(0, from1.indexOf("@"));
555
556
		const flag = document.createElement("abbr");
557
		flag.textContent = getCountryFlag(cc);
558
		flag.title = getCountryName(cc);
559
		cellSnd2.appendChild(flag);
560
561
		const fromText = document.createElement("span");
562
		fromText.textContent = " " + from2;
563
		cellSnd2.appendChild(fromText);
564
	}
565
566
	row.onclick = function() {
567
		displayMsg(isInt, i);
568
	};
569
}
570
571
function getRowsPerPage() {
572
	const tbl = document.getElementById("tbl_inbox");
573
	tbl.innerHTML = "";
574
	const row = tbl.insertRow(-1);
575
	const cell = row.insertCell(-1);
576
	cell.textContent = "0";
577
578
	const rowsPerPage = Math.floor(getComputedStyle(document.getElementById("div_inbox")).height.replace("px", "") / getComputedStyle(document.querySelector("#tbl_inbox > tbody > tr:first-child")).height.replace("px", "")) - 1; // -1 allows space for 'load more'
579
	tbl.innerHTML = "";
580
	return rowsPerPage;
581
}
582
583
function addMessages() {
584
	const rowsPerPage = getRowsPerPage();
585
	let skipMsgs = rowsPerPage * tabs[TAB_INBOX].cur;
586
587
	const maxExt = ae.GetExtMsgCount();
588
	const maxInt = ae.GetIntMsgCount();
589
590
	tabs[TAB_INBOX].max = Math.floor((maxExt + maxInt - 1) / rowsPerPage);
591
592
	let numExt = 0;
593
	let numInt = 0;
594
	let numAdd = 0;
595
596
	while (numAdd < rowsPerPage) {
597
		const tsInt = (numInt < maxInt) ? ae.GetIntMsgTime(numInt) : -1;
598
		const tsExt = (numExt < maxExt) ? ae.GetExtMsgTime(numExt) : -1;
599
		if (tsInt === -1 && tsExt === -1) break;
600
601
		if (tsInt !== -1 && (tsExt === -1 || tsInt > tsExt)) {
602
			if (skipMsgs > 0) skipMsgs--; else {addMsg(true, numInt); numAdd++;}
603
			numInt++;
604
		} else if (tsExt !== -1) {
605
			if (skipMsgs > 0) skipMsgs--; else {addMsg(false, numExt); numAdd++;}
606
			numExt++;
607
		}
608
	}
609
610
	if (ae.GetReadyMsgBytes() < ae.GetTotalMsgBytes()) {
611
		const inbox = document.getElementById("tbl_inbox");
612
		const row = inbox.insertRow(-1);
613
		const cell = row.insertCell(-1);
614
		cell.textContent = "Load more (" + (ae.GetTotalMsgBytes() - ae.GetReadyMsgBytes()) / 1024 + " KiB left)";
615
616
		row.onclick = function() {
617
			this.onclick = "";
618
619
			ae.Message_Browse(false, false, function(successBrowse) {
620
				document.getElementById("tbl_inbox").style.opacity = 1;
621
622
				if (successBrowse) {
623
					addMessages();
624
					addUploads();
625
					addSent();
626
					if (tabs[tab].cur < tabs[tab].max) document.getElementById("btn_rght").disabled = false;
627
				}
628
			});
629
		};
630
	}
631
}
632
633
function addUploads() {
634
	const tbl = document.getElementById("tbd_uploads");
635
	tbl.innerHTML = "";
636
637
	for (let i = 0; i < ae.GetUplMsgCount(); i++) {
638
		const row = tbl.insertRow(-1);
639
		row.setAttribute("data-msgid", ae.GetUplMsgIdHex(i));
640
641
		let cell;
642
		cell = row.insertCell(-1); cell.textContent = new Date(ae.GetUplMsgTime(i) * 1000).toISOString().slice(0, 10);
643
644
		cell = row.insertCell(-1); cell.textContent = ae.GetUplMsgTitle(i);
645
		cell.onclick = function() {displayFile(this.parentElement.rowIndex - 1);};
646
647
		cell = row.insertCell(-1); cell.textContent = (ae.GetUplMsgBytes(i) / 1024).toFixed(1);
648
649
		cell = row.insertCell(-1);
650
		if (ae.GetUplMsgIdHex(i)) {
651
			cell.innerHTML = "<button data-msgid=\"" + ae.GetUplMsgIdHex(i) + "\" type=\"button\">X</button>";
652
653
			cell.children[0].onclick = function() {
654
				const tr = this.parentElement.parentElement;
655
				ae.Message_Delete(this.getAttribute("data-msgid"), function(success) {
656
					if (success) tr.remove();
657
				});
658
			};
659
		}
660
	}
661
}
662
663
function displayOutMsg(num) {
664
	clearDisplay();
665
	document.getElementById("midright").scroll(0, 0);
666
	document.getElementById("midright").setAttribute("data-msgid", ae.GetOutMsgIdHex(num));
667
	document.getElementById("btn_reply").disabled = true;
668
	document.getElementById("btn_mdele").disabled = false;
669
	document.getElementById("midright").children[0].hidden = false;
670
	document.getElementById("midright").children[2].hidden = false;
671
672
	document.getElementById("midright").children[1].textContent = ae.GetOutMsgSubj(num);
673
	document.getElementById("midright").children[2].textContent = ae.GetOutMsgBody(num);
674
675
	document.getElementById("readmsg_envto").textContent = ae.GetOutMsgTo(num);
676
	document.getElementById("readmsg_envfrom").textContent = ae.GetOutMsgFrom(num);
677
678
	const ts = ae.GetOutMsgTime(num);
679
	const tzOs = new Date().getTimezoneOffset();
680
	const tz = ((tzOs < 0) ? "+" : "-") + Math.floor(tzOs / -60).toString().padStart(2, "0") + (tzOs % 60 * -1).toString().padStart(2, "0");
681
	document.getElementById("readmsg_date").children[0].textContent = new Date((ts * 1000) + (tzOs * -60000)).toISOString().slice(0, 19).replace("T", " ") + " " + tz;
682
683
	const isInt = ae.GetOutMsgIsInt(num);
684
	document.getElementById("readmsg_ip").hidden      = isInt;
685
	document.getElementById("readmsg_country").hidden = isInt;
686
	document.getElementById("readmsg_tls").hidden     = isInt;
687
	document.getElementById("readmsg_greet").hidden   = isInt;
688
689
	if (!isInt) {
690
//		const cc = ae.GetExtMsgCountry(num);
691
692
		document.getElementById("readmsg_ip").children[0].textContent = ae.GetOutMsgIp(num);
693
//		document.getElementById("readmsg_country").textContent = getCountryFlag(cc) + " " + getCountryName(cc);
694
//		document.getElementById("readmsg_tls").children[0].textContent = ae.GetOutMsgTLS(num);
695
		document.getElementById("readmsg_greet").children[0].textContent = ae.GetOutMsgGreet(num);
696
	}
697
698
	let flagText = "";
699
	if (!ae.GetOutMsgFlagVPad(num)) flagText += "<abbr title=\"Invalid padding\">PAD</abbr> ";
700
	if (!ae.GetOutMsgFlagVSig(num)) flagText += "<abbr title=\"Invalid signature\">SIG</abbr> ";
701
	if (ae.GetOutMsgFlagE2ee(num)) flagText += "<abbr title=\"End-to-end encrypted\">E2EE</abbr> ";
702
	document.getElementById("readmsg_flags").children[0].innerHTML = flagText.trim();
703
}
704
705
function addSent() {
706
	const tbl = document.getElementById("tbl_drbox");
707
	tbl.innerHTML = "";
708
709
	for (let i = 0; i < ae.GetOutMsgCount(); i++) {
710
		const row = tbl.insertRow(-1);
711
		row.setAttribute("data-msgid", ae.GetOutMsgIdHex(i));
712
713
		let cell;
714
		cell = row.insertCell(-1); cell.textContent = new Date(ae.GetOutMsgTime(i) * 1000).toISOString().slice(0, 10);
715
		cell = row.insertCell(-1); cell.textContent = ae.GetOutMsgSubj(i);
716
		row.onclick = function() {displayOutMsg(i);};
717
	}
718
}
719
720
function updateAddressCounts() {
721
	document.getElementById("limit_normal").textContent = (ae.GetAddressCountNormal() + "/" + ae.GetLimitNormalA(ae.GetUserLevel())).padStart(ae.GetLimitNormalA(ae.GetUserLevel()) > 9 ? 5 : 1);
722
	document.getElementById("limit_shield").textContent = (ae.GetAddressCountShield() + "/" + ae.GetLimitShieldA(ae.GetUserLevel())).padStart(ae.GetLimitShieldA(ae.GetUserLevel()) > 9 ? 5 : 1);
723
	document.getElementById("limit_total").textContent = ((ae.GetAddressCountNormal() + ae.GetAddressCountShield()) + "/" + ae.GetAddrPerUser()).padStart(5);
724
}
725
726
function adjustLevel(pubkey, level, c) {
727
	const fs = document.getElementById("fs_accs");
728
	fs.disabled = true;
729
730
	ae.Account_Update(pubkey, level, function(success) {
731
		fs.disabled = false;
732
733
		if (success) {
734
			c[4].textContent = level;
735
			c[5].children[0].disabled = (level === 3);
736
			c[6].children[0].disabled = (level === 0);
737
		}
738
	});
739
}
740
741
function addAccountToTable(i) {
742
	const tblAccs = document.getElementById("tbd_accs");
743
	const row = tblAccs.insertRow(-1);
744
	let cell;
745
	cell = row.insertCell(-1); cell.textContent = ae.Admin_GetUserPkHex(i);
746
	cell = row.insertCell(-1); cell.textContent = ae.Admin_GetUserSpace(i);
747
	cell = row.insertCell(-1); cell.textContent = ae.Admin_GetUserNAddr(i);
748
	cell = row.insertCell(-1); cell.textContent = ae.Admin_GetUserSAddr(i);
749
	cell = row.insertCell(-1); cell.textContent = ae.Admin_GetUserLevel(i);
750
751
	cell = row.insertCell(-1); cell.innerHTML = "<button type=\"button\" autocomplete=\"off\">+</button>";
752
	cell.children[0].onclick = function() {const c = this.parentElement.parentElement.cells; adjustLevel(c[0].textContent, parseInt(c[4].textContent) + 1, c);};
753
	cell.children[0].disabled = (ae.Admin_GetUserLevel(i) === 3);
754
755
	cell = row.insertCell(-1); cell.innerHTML = "<button type=\"button\" autocomplete=\"off\">&minus;</button>";
756
	cell.children[0].onclick = function() {const c = this.parentElement.parentElement.cells; adjustLevel(c[0].textContent, parseInt(c[4].textContent) - 1, c);};
757
	cell.children[0].disabled = (ae.Admin_GetUserLevel(i) === 0);
758
759
	cell = row.insertCell(-1); cell.innerHTML = "<button type=\"button\" autocomplete=\"off\">X</button>";
760
	cell.children[0].onclick = function() {
761
		const tr = this.parentElement.parentElement;
762
		ae.Account_Delete(tr.cells[0].textContent, function(success) {
763
			if (success) tr.remove();
764
		});
765
	};
766
}
767
768
function reloadAccount() {
769
	// Limits
770
	const tblLimits = document.getElementById("tbl_limits");
771
	if (ae.IsUserAdmin()) {
772
		for (let i = 0; i < 4; i++) {
773
			tblLimits.rows[i].cells[1].children[0].disabled = false;
774
			tblLimits.rows[i].cells[2].children[0].disabled = false;
775
			tblLimits.rows[i].cells[3].children[0].disabled = false;
776
777
			tblLimits.rows[i].cells[1].children[0].value = ae.GetLimitStorage(i) + 1;
778
			tblLimits.rows[i].cells[2].children[0].value = ae.GetLimitNormalA(i);
779
			tblLimits.rows[i].cells[3].children[0].value = ae.GetLimitShieldA(i);
780
		}
781
	} else {
782
		const lvl = ae.GetUserLevel();
783
		tblLimits.rows[lvl].cells[1].children[0].value = ae.GetLimitStorage(lvl) + 1;
784
		tblLimits.rows[lvl].cells[2].children[0].value = ae.GetLimitNormalA(lvl);
785
		tblLimits.rows[lvl].cells[3].children[0].value = ae.GetLimitShieldA(lvl);
786
	}
787
788
	// Accounts
789
	const tblAccs = document.getElementById("tbd_accs");
790
791
	// All: Our account
792
	const row = tblAccs.insertRow(-1);
793
	let cell;
794
	cell = row.insertCell(-1); cell.textContent = ae.GetUserPkHex();
795
	cell = row.insertCell(-1); cell.textContent = Math.round(ae.GetTotalMsgBytes() / 1024 / 1024);
796
	cell = row.insertCell(-1); cell.textContent = ae.GetAddressCountNormal();
797
	cell = row.insertCell(-1); cell.textContent = ae.GetAddressCountShield();
798
	cell = row.insertCell(-1); cell.textContent = ae.GetUserLevel();
799
	cell = row.insertCell(-1); cell.innerHTML = "<button type=\"button\" autocomplete=\"off\" disabled=\"disabled\">+</button>";
800
801
	cell = row.insertCell(-1); cell.innerHTML = "<button id=\"btn_downme\" type=\"button\" autocomplete=\"off\" disabled=\"disabled\">&minus;</button>";
802
	cell.children[0].onclick = function() {
803
		const newLevel = parseInt(row.cells[4].textContent) - 1;
804
		ae.Account_Update(ae.GetUserPkHex(), newLevel, function(success) {
805
			if (success) row.cells[4].textContent = newLevel;
806
		});
807
	};
808
809
	cell = row.insertCell(-1); cell.innerHTML = "<button id=\"btn_killme\" type=\"button\" autocomplete=\"off\" disabled=\"disabled\">X</button>";
810
	cell.children[0].onclick = function() {
811
		ae.Account_Delete(ae.GetUserPkHex(), function(success) {
812
			if (success) row.remove();
813
		});
814
	};
815
816
	document.getElementById("txt_reg").disabled = !ae.IsUserAdmin();
817
	document.getElementById("btn_reg").disabled = !ae.IsUserAdmin();
818
819
	// Contacts
820
	for (let i = 0; i < ae.GetContactCount(); i++) {
821
		addContact(
822
			ae.GetContactMail(i),
823
			ae.GetContactName(i),
824
			ae.GetContactNote(i)
825
		);
826
	}
827
828
	// Addresses
829
	for (let i = 0; i < ae.GetAddressCount(); i++) {
830
		addAddress(i);
831
	}
832
833
	updateAddressCounts();
834
	addMessages();
835
	addUploads();
836
	addSent();
837
838
	document.getElementById("btn_rght").disabled = (tabs[tab].cur === tabs[tab].max);
839
}
840
841
function deleteAddress(addr) {
842
	let btns = document.getElementById("tbl_addrs").getElementsByTagName("button");
843
	for (let i = 0; i < btns.length; i++) btns[i].disabled = true;
844
845
	let addressToDelete = -1;
846
847
	for (let i = 0; i < ae.GetAddressCount(); i++) {
848
		if (addr === ae.GetAddress(i)) {
849
			addressToDelete = i;
850
			break;
851
		}
852
	}
853
854
	if (addressToDelete === -1) return;
855
856
	ae.Address_Delete(addressToDelete, function(success) {
857
		if (success) {
858
			document.getElementById("tbl_addrs").deleteRow(addressToDelete);
859
			document.getElementById("write_from").remove(addressToDelete);
860
			updateAddressCounts();
861
862
			const limitReached = (ae.GetAddressCountNormal() + ae.GetAddressCountShield() >= 31);
863
			document.getElementById("btn_address_create_normal").disabled = (limitReached || ae.GetAddressCountNormal() > ae.GetLimitNormalA(ae.GetUserLevel()));
864
			document.getElementById("btn_address_create_shield").disabled = (limitReached || ae.GetAddressCountShield() > ae.GetLimitShieldA(ae.GetUserLevel()));
865
866
			ae.Private_Update(function(success2) {
867
				if (!success2) console.log("Failed to update the Private field");
868
869
				btns = document.getElementById("tbl_addrs").getElementsByTagName("button");
870
				for (let i = 0; i < btns.length; i++) btns[i].disabled = false;
871
			});
872
		} else {
873
			console.log("Failed to delete address");
874
875
			btns = document.getElementById("tbl_addrs").getElementsByTagName("button");
876
			for (let i = 0; i < btns.length; i++) btns[i].disabled = false;
877
		}
878
	});
879
}
880
881 View Code Duplication
function shieldMix(addr) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
882
	let newAddr = "";
883
884
	for (let i = 0; i < 16; i++) {
885
		switch (addr.charAt(i)) {
886
			case '1':
887
				newAddr += "1iIlL".charAt(Math.floor(Math.random() * 5));
888
				break;
889
			case '0':
890
				newAddr += "0oO".charAt(Math.floor(Math.random() * 3));
891
				break;
892
			case 'w':
893
				newAddr += "VvWw".charAt(Math.floor(Math.random() * 4));
894
				break;
895
			default:
896
				newAddr += (Math.random() > 0.5) ? addr.charAt(i) : addr.charAt(i).toUpperCase();
897
		}
898
	}
899
900
	return newAddr;
901
}
902
903
function addAddress(num) {
904
	const addrTable = document.getElementById("tbl_addrs");
905
	const row = addrTable.insertRow(-1);
906
	const cellAddr = row.insertCell(-1);
907
	const cellChk1 = row.insertCell(-1);
908
	const cellChk2 = row.insertCell(-1);
909
	const cellBtnD = row.insertCell(-1);
910
911
	cellAddr.textContent = ae.GetAddress(num);
912
	cellAddr.onclick = function() {
913
		if (cellAddr.textContent.length === 16)
914
			navigator.clipboard.writeText(shieldMix(cellAddr.textContent) + "@" + ae.GetDomainEml());
1 ignored issue
show
Bug introduced by
The variable navigator seems to be never declared. If this is a global, consider adding a /** global: navigator */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
915
		else
916
			navigator.clipboard.writeText(cellAddr.textContent + "@" + ae.GetDomainEml());
917
	};
918
919
	cellChk1.innerHTML = ae.GetAddressAccExt(num) ? "<input type=\"checkbox\" checked=\"checked\">" : "<input type=\"checkbox\">";
920
	cellChk2.innerHTML = ae.GetAddressAccInt(num) ? "<input type=\"checkbox\" checked=\"checked\">" : "<input type=\"checkbox\">";
921
922
	cellBtnD.innerHTML = "<button type=\"button\">X</button>";
923
	cellBtnD.onclick = function() {deleteAddress(cellAddr.textContent);};
924
925
	const opt = document.createElement("option");
926
	opt.value = cellAddr.textContent;
927
	opt.textContent = cellAddr.textContent + "@" + ae.GetDomainEml();
928
	document.getElementById("write_from").appendChild(opt);
929
}
930
931
document.getElementById("btn_dele").onclick = function() {
932
	this.blur();
933
934
	if (tab === TAB_WRITE) {
935
		tabs[tab].cur = 0;
936
		updateTab();
937
938
		document.getElementById("write_recv").value = "";
939
		document.getElementById("write_subj").value = "";
940
		document.getElementById("write_body").value = "";
941
942
		document.getElementById("write_recv").readOnly = false;
943
		document.getElementById("write_subj").readOnly = false;
944
		document.getElementById("write_subj").setAttribute("data-replyid", "");
945
946
		document.getElementById("write_recv").focus();
947
	}
948
};
949
950
document.getElementById("btn_updt").onclick = function() {
951
	const btn = this;
952
	btn.disabled = true;
953
	btn.blur();
954
955
	if (tab === TAB_INBOX) {
956
		document.getElementById("tbl_inbox").style.opacity = 0.5;
957
958
		ae.Message_Browse(true, false, function(successBrowse) {
959
			document.getElementById("tbl_inbox").style.opacity = 1;
960
961
			if (successBrowse) {
962
				addMessages();
963
				addUploads();
964
				btn.disabled = false;
965
			} else {
966
				console.log("Failed to refresh");
967
				btn.disabled = false;
968
			}
969
		});
970
	}
971
};
972
973
document.getElementById("btn_mdele").onclick = function() {
974
	const btn = this;
975
	btn.blur();
976
	btn.disabled = true;
977
978
	const delId = document.getElementById("midright").getAttribute("data-msgid");
979
	if (!delId) return;
980
981
	ae.Message_Delete(delId, function(success) {
982
		if (success) {
983
			["tbl_inbox", "tbl_drbox", "tbd_uploads"].forEach(function(tbl_name) {
984
				const tbl = document.getElementById(tbl_name);
985
				for (let i = 0; i < tbl.rows.length; i++) {if (tbl.rows[i].getAttribute("data-msgid") === delId) tbl.deleteRow(i);}
986
			});
987
988
			addMessages();
989
			addUploads();
990
			addSent();
991
		} else btn.disabled = false;
992
	});
993
};
994
995
function addContact(mail, name, note) {
996
	const tbl = document.getElementById("tbl_ctact");
997
	const row = tbl.insertRow(-1);
998
	const cellMail = row.insertCell(-1);
999
	const cellName = row.insertCell(-1);
1000
	const cellNote = row.insertCell(-1);
1001
	const cellBtnD = row.insertCell(-1);
1002
1003
	cellMail.textContent = mail;
1004
	cellName.textContent = name;
1005
	cellNote.textContent = note;
1006
	cellBtnD.innerHTML = "<button type=\"button\">X</button>";
1007
1008
	cellMail.contentEditable = true;
1009
	cellName.contentEditable = true;
1010
	cellNote.contentEditable = true;
1011
1012
	cellBtnD.onclick = function() {row.remove();};
1013
}
1014
1015
document.getElementById("btn_newcontact").onclick = function() {
1016
	addContact("", "", "");
1017
};
1018
1019
document.getElementById("btn_savecontacts").onclick = function() {
1020
	while (ae.GetContactCount() > 0) {
1021
		ae.DeleteContact(0);
1022
	}
1023
1024
	for (const row of document.getElementById("tbl_ctact").rows) {
1025
		ae.AddContact(row.cells[0].textContent, row.cells[1].textContent, row.cells[2].textContent);
1026
	}
1027
1028
	const btn = this;
1029
	btn.disabled = true;
1030
1031
	ae.Private_Update(function(success) {
1032
		btn.disabled = false;
1033
1034
		if (!success) {
1035
			console.log("Failed contacts update");
1036
		}
1037
	});
1038
};
1039
1040
function writeVerify() {
1041
	document.getElementById("div_write_1").hidden = true;
1042
	document.getElementById("div_write_2").hidden = false;
1043
1044
	document.getElementById("write2_recv").textContent = document.getElementById("write_recv").value;
1045
	document.getElementById("write2_subj").textContent = document.getElementById("write_subj").value;
1046
	document.getElementById("write2_rply").textContent = document.getElementById("write_subj").getAttribute("data-replyid");
1047
	document.getElementById("write2_body").textContent = document.getElementById("write_body").value;
1048
1049
	if (document.getElementById("write_recv").value.indexOf("@") >= 0) {
1050
		document.getElementById("write2_from").textContent = document.getElementById("write_from").value + "@" + ae.GetDomainEml();
1051
		document.getElementById("write2_pkey").hidden = true;
1052
	} else {
1053
		document.getElementById("write2_from").textContent = document.getElementById("write_from").value;
1054
		document.getElementById("write2_pkey").hidden = false;
1055
	}
1056
}
1057
1058
function updateTab() {
1059
	switch (tab) {
1060
		case TAB_INBOX:
1061
			addMessages();
1062
		break;
1063
1064
		case TAB_DRBOX:
1065
			addSent();
1066
		break;
1067
1068
		case TAB_WRITE:
1069
			switch (tabs[tab].cur) {
1070
				case 0: // Write
1071
					document.getElementById("div_write_1").hidden = false;
1072
					document.getElementById("div_write_2").hidden = true;
1073
					document.getElementById("write_body").focus();
1074
				break;
1075
1076
				case 1: // Verify
1077
					writeVerify();
1078
				break;
1079
1080
				case 2: // Send
1081
					ae.Message_Create(
1082
						document.getElementById("write_subj").value,
1083
						document.getElementById("write_body").value,
1084
						document.getElementById("write_from").value,
1085
						document.getElementById("write_recv").value,
1086
						document.getElementById("write_subj").getAttribute("data-replyid"),
1087
						(document.getElementById("write2_recv").textContent.indexOf("@") > 0) ? null : sodium.from_base64(document.querySelector("#write2_pkey > input").value, sodium.base64_variants.ORIGINAL_NO_PADDING),
1 ignored issue
show
Bug introduced by
The variable sodium seems to be never declared. If this is a global, consider adding a /** global: sodium */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1088
						function(success) {
1089
							if (success) {
1090
								console.log("Sent ok");
1091
							} else {
1092
								console.log("Failed sending");
1093
							}
1094
						}
1095
					);
1096
				break;
1097
			}
1098
		break;
1099
1100
		case TAB_NOTES:
1101
			for (let i = 0; i <= tabs[tab].max; i++) {
1102
				document.getElementById("div_notes").children[i].hidden = (i !== tabs[tab].cur);
1103
			}
1104
		break;
1105
1106
		case TAB_TOOLS:
1107
			for (let i = 0; i <= tabs[tab].max; i++) {
1108
				document.getElementById("div_tools").children[i].hidden = (i !== tabs[tab].cur);
1109
			}
1110
		break;
1111
	}
1112
1113
	document.getElementById("btn_left").disabled = (tabs[tab].cur === 0);
1114
	document.getElementById("btn_rght").disabled = (tabs[tab].cur === tabs[tab].max);
1115
}
1116
1117
document.getElementById("btn_left").onclick = function() {
1118
	tabs[tab].cur--;
1119
	if (tabs[tab].cur === 0) this.disabled = true;
1120
	if (tabs[tab].cur < tabs[tab].max) document.getElementById("btn_rght").disabled = false;
1121
	updateTab();
1122
	this.blur();
1123
};
1124
1125
document.getElementById("btn_rght").onclick = function() {
1126
	tabs[tab].cur++;
1127
	if (tabs[tab].cur === tabs[tab].max) this.disabled = true;
1128
	document.getElementById("btn_left").disabled = false;
1129
	updateTab();
1130
	this.blur();
1131
};
1132
1133
const buttons = document.querySelector("#main1 > .top").getElementsByTagName("button");
1134
for (let i = 0; i < buttons.length; i++) {
1135
	buttons[i].onclick = function() {
1136
		tab = i;
1137
1138
		for (let j = 0; j < buttons.length; j++) {
1139
			document.querySelector("#main1 > .mid").children[j].hidden = (tab !== j);
1140
			buttons[j].disabled = (tab === j);
1141
		}
1142
1143
		document.getElementById("btn_left").disabled = (tabs[tab].cur === 0);
0 ignored issues
show
Bug introduced by
The variable tab is changed as part of the for loop for example by i on line 1136. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
1144
		document.getElementById("btn_rght").disabled = (tabs[tab].cur === tabs[tab].max);
1145
		document.getElementById("btn_dele").disabled = !tabs[tab].btnDele;
1146
		document.getElementById("btn_updt").disabled = !tabs[tab].btnUpdt;
1147
1148
		updateTab();
1149
	};
1150
}
1151
1152
function addressCreate(addr) {
1153
	const btnN = document.getElementById("btn_address_create_normal");
1154
	const btnS = document.getElementById("btn_address_create_shield");
1155
	btnN.disabled = true;
1156
	btnS.disabled = true;
1157
1158
	ae.Address_Create(addr, function(success1) {
1159
		if (success1) {
1160
			ae.Private_Update(function(success2) {
1161
				addAddress(ae.GetAddressCount() - 1);
1162
				if (addr !== "SHIELD") document.getElementById("txt_address_create_normal").value = "";
1163
				updateAddressCounts();
1164
1165
				if (!success2) console.log("Failed to update the Private field");
1166
1167
				const limitReached = (ae.GetAddressCountNormal() + ae.GetAddressCountShield() >= 31);
1168
				btnN.disabled = (limitReached || ae.GetAddressCountNormal() >= ae.GetLimitNormalA(ae.GetUserLevel()));
1169
				btnS.disabled = (limitReached || ae.GetAddressCountShield() >= ae.GetLimitShieldA(ae.GetUserLevel()));
1170
			});
1171
		} else {
1172
			console.log("Failed to add address");
1173
1174
			const limitReached = (ae.GetAddressCountNormal() + ae.GetAddressCountShield() >= 31);
1175
			btnN.disabled = (limitReached || ae.GetAddressCountNormal() >= ae.GetLimitNormalA(ae.GetUserLevel()));
1176
			btnS.disabled = (limitReached || ae.GetAddressCountShield() >= ae.GetLimitShieldA(ae.GetUserLevel()));
1177
		}
1178
	});
1179
}
1180
1181
document.getElementById("btn_address_create_normal").onclick = function() {
1182
	if (ae.GetAddressCountNormal() >= ae.GetLimitNormalA(ae.GetUserLevel()) || ae.GetAddressCountNormal() + ae.GetAddressCountShield() >= 31) return;
1183
1184
	const txtNewAddr = document.getElementById("txt_address_create_normal");
1185
	if (!txtNewAddr.reportValidity()) return;
1186
1187
	addressCreate(txtNewAddr.value);
1188
};
1189
1190
document.getElementById("btn_address_create_shield").onclick = function() {
1191
	if (ae.GetAddressCountShield() >= ae.GetLimitShieldA(ae.GetUserLevel()) || ae.GetAddressCountNormal() + ae.GetAddressCountShield() >= 31) return;
1192
1193
	addressCreate("SHIELD");
1194
};
1195
1196
document.getElementById("btn_address_update").onclick = function() {
1197
	const btn = this;
1198
	btn.disabled = true;
1199
1200
	const rows = document.getElementById("tbl_addrs").rows;
1201
1202
	for (let i = 0; i < rows.length; i++) {
1203
		ae.SetAddressAccExt(i, rows[i].getElementsByTagName("input")[0].checked);
1204
		ae.SetAddressAccInt(i, rows[i].getElementsByTagName("input")[1].checked);
1205
	}
1206
1207
	ae.Address_Update(function(success) {
1208
		if (!success) console.log("Address/Update failed");
1209
		btn.disabled = false;
1210
	});
1211
};
1212
1213
document.getElementById("btn_reg").onclick = function() {
1214
	const btn = document.getElementById("btn_reg");
1215
	const txt = document.getElementById("txt_reg");
1216
	if (!txt.reportValidity()) return;
1217
	btn.disabled = true;
1218
1219
	ae.Account_Create(txt.value, function(success) {
1220
		if (success) {
1221
			addAccountToTable(ae.Admin_GetUserCount() - 1);
1222
			txt.value = "";
1223
		}
1224
1225
		btn.disabled = false;
1226
	});
1227
};
1228
1229
document.getElementById("chk_downme").onclick = function() {document.getElementById("btn_downme").disabled = !this.checked;};
1230
document.getElementById("chk_killme").onclick = function() {document.getElementById("btn_killme").disabled = !this.checked;};
1231
1232
document.getElementById("btn_notepad_saveupl").onclick = function() {
1233
	const np = document.getElementById("txt_notepad");
1234
	np.disabled = true;
1235
1236
	let fname = prompt("Save as...", "Untitled");
0 ignored issues
show
Debugging Code Best Practice introduced by
The prompt UI element is often considered obtrusive and is generally only used as a temporary measure. Consider replacing it with another UI element.
Loading history...
1237
	if (!fname.endsWith(".txt")) fname += ".txt";
1238
1239
	ae.Message_Upload(fname, np.value, function(success) {
1240
		if (success) {
1241
			np.value = "";
1242
			addUploads();
1243
			document.getElementById("tbd_accs").children[0].children[1].textContent = Math.round(ae.GetTotalMsgBytes() / 1024 / 1024);
1244
		}
1245
1246
		console.log("Failed to add text");
1247
		np.disabled = false;
1248
	});
1249
};
1250
1251
document.getElementById("btn_upload").onclick = function() {
1252
	const btn = this;
1253
	const fileSelector = document.createElement("input");
1254
	fileSelector.type = "file";
1255
	fileSelector.click();
1256
1257
	fileSelector.onchange = function() {
1258
		btn.disabled = true;
1259
1260
		const reader = new FileReader();
1 ignored issue
show
Bug introduced by
The variable FileReader seems to be never declared. If this is a global, consider adding a /** global: FileReader */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1261
		reader.onload = function() {
1262
			ae.Message_Upload(fileSelector.files[0].name, new Uint8Array(reader.result), function(success) {
1263
				if (success) {
1264
					addUploads();
1265
					document.getElementById("tbd_accs").children[0].children[1].textContent = Math.round(ae.GetTotalMsgBytes() / 1024 / 1024);
1266
				} else {
1267
					console.log("Failed upload");
1268
				}
1269
1270
				btn.disabled = false;
1271
			});
1272
		};
1273
1274
		reader.readAsArrayBuffer(fileSelector.files[0]);
1275
	};
1276
};
1277
1278
document.getElementById("btn_pg").onclick = function() {
1279
	localStorage.greeting = document.getElementById("txt_pg").value;
1 ignored issue
show
Bug introduced by
The variable localStorage seems to be never declared. If this is a global, consider adding a /** global: localStorage */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1280
};
1281
1282
document.getElementById("txt_skey").onkeyup = function(event) {
1283
	if (event.key === "Enter") {
1284
		event.preventDefault();
1285
		document.getElementById("btn_enter").click();
1286
	}
1287
};
1288
1289
document.getElementById("btn_enter").onclick = function() {
1290
	const txtSkey = document.getElementById("txt_skey");
1291
	if (!txtSkey.reportValidity()) return;
1292
1293
	const btn = this;
1294
	btn.disabled = true;
1295
	document.getElementById("txt_skey").style.background = "#233";
1296
1297
	ae.SetKeys(txtSkey.value, function(successSetKeys) {
1298
		if (successSetKeys) {
1299
			ae.Message_Browse(false, true, function(successBrowse) {
1300
				if (successBrowse) {
1301
					txtSkey.value = "";
1302
					document.getElementById("div_begin").hidden = true;
1303
					document.getElementById("div_main").style.display = "grid";
1304
					reloadAccount();
1305
1306
					if (ae.IsUserAdmin()) {
1307
						ae.Account_Browse(function(successAcc) {
1308
							if (successAcc) {for (let i = 0; i < ae.Admin_GetUserCount(); i++) {addAccountToTable(i);}}
1309
							else console.log("Failed to Account_Browse");
1310
						});
1311
					}
1312
				} else {
1313
					console.log("Failed to enter");
1314
					btn.disabled = false;
1315
					document.getElementById("txt_skey").style.background = "#466";
1316
					txtSkey.focus();
1317
				}
1318
			});
1319
		} else {
1320
			console.log("Invalid format for key");
1321
			btn.disabled = false;
1322
			document.getElementById("txt_skey").style.background = "#466";
1323
			txtSkey.focus();
1324
		}
1325
	});
1326
};
1327
1328
});
1329